﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ServiceLocation;
using YasharEl.Infrastructure.Diagnostics.Logging;

namespace YasharEl.Infrastructure.ObjectFactory
{
    public static class DependencyContainer
    {
        static volatile bool initialized;

        public static bool Initialized
        {
            get
            {
                return initialized;
            }
            set
            {
                initialized = value;
            }
        }

        private static IDependencyRegistrar Registrar
        {
            get { return ServiceLocator.Current.GetInstance<IDependencyRegistrar>(); }
        }

        private static IDependencyResolver Resolver
        {
            get { return ServiceLocator.Current.GetInstance<IDependencyResolver>(); }
        }

        public static TInterface Resolve<TInterface>()
        {
            return Resolver.Resolve<TInterface>();
        }

        public static TInterface Resolve<TInterface>(string key)
        {
            return Resolver.Resolve<TInterface>(key);
        }

        public static object Resolve(Type objectType)
        {
            return Resolver.Resolve(objectType);
        }

        private static object Resolve(Type objectType, string key)
        {
            return Resolver.Resolve(objectType, key);
        }

        public static bool TryResolve(out object result, Type objectType, string key = null)
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                {
                    if (Registrar.IsTypeRegistered(objectType))
                    {
                        result = Resolve(objectType);
                    }
                    else
                    {
                        result = null;
                    }
                }
                else
                {
                    if (Registrar.IsTypeRegistered(objectType, key))
                    {
                        result = Resolve(objectType, key);
                    }
                    else
                    {
                        result = null;
                    }
                }
            }
            catch (Exception e)
            {
                /*  Unable to be more specific because  we 
                 *  don't know the container implementation. */
                LogResolvingException(e, objectType);
                result = null;
            }
            return result != null;
        }

        public static bool TryResolve<TInterface>(out TInterface result, string key = null)
            where TInterface : class
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                {
                    if (Registrar.IsTypeRegistered(typeof(TInterface)))
                    {
                        result = Resolve<TInterface>();
                    }
                    else
                    {
                        result = null;
                    }
                }
                else
                {
                    if (Registrar.IsTypeRegistered(typeof(TInterface), key))
                    {
                        result = Resolve<TInterface>(key);
                    }
                    else
                    {
                        result = null;
                    }
                }
            }
            catch (Exception e)
            {
                /*  Unable to be more specific because  we 
                *  don't know the container implementation. */

                LogResolvingException(e, typeof(TInterface));

                result = null;
            }
            return result != null;
        }

        private static void LogResolvingException(Exception exception, Type objectToResolveType)
        {
            // Try to log exception ( if logger may be resolved...)
            bool isLogged = false;
            string message = string.Format("Resolving {0} failed due to an error {1}.", objectToResolveType, exception);
            try
            {
                ILogger<IDependencyContainer> logger = Resolve<ILogger<IDependencyContainer>>();
                if (logger != null)
                {
                    logger.Error(message);
                    isLogged = true;
                }
            }
            finally
            {
                if (!isLogged)
                {
                    System.Diagnostics.Trace.WriteLine(message);
                }
            }
        }
    }
}
